﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Shell;
using System.Windows.Threading;
using Home.Base;
using Weather.Base;
using Weather.Controls;
using Weather.Domain;
using System.Windows.Media.Animation;
using System.IO;

namespace Weather.Windows
{
    /// <summary>
    /// Interaction logic for WeatherWidget.xaml
    /// </summary>
    public partial class WeatherMetro : Window
    {
        private IntPtr handle;
        private WeatherData currentWeather;
        private LocationData currentLocation;
        private DispatcherTimer weatherTimer;
        private Options optionsWindow;
        private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
        private WeatherState lastWeatherState;

        public WeatherMetro()
        {
            InitializeComponent();
        }

        private void WindowSourceInitialized(object sender, EventArgs e)
        {
            handle = new WindowInteropHelper(this).Handle;

            if (!App.Settings.DisableUnminimizer)
            {
                var u = new Unminimizer();
                u.Initialize(handle);
            }

            Dwm.RemoveFromAeroPeek(handle);
            Dwm.RemoveFromAltTab(handle);
            Dwm.RemoveFromFlip3D(handle);

            this.Left = App.Settings.Left;
            this.Top = App.Settings.Top;

            if (this.Left == -100.0f || this.Top == -100.0f)
            {
                this.Left = SystemParameters.WorkArea.Width / 2 - this.Width / 2;
                this.Top = SystemParameters.WorkArea.Height / 2 - this.Height / 2;
            }

            Scale.ScaleX = App.Settings.Scale;
            this.Opacity = App.Settings.Opacity;

            if (App.Settings.UseAero)
            {
                UpdateAero();
            }

            if (App.Settings.TopMost)
            {
                this.Topmost = true;
                TopMostItem.IsChecked = true;
            }

            if (App.Settings.Pin)
                PinItem.IsChecked = true;
        }

        private void WindowLoaded(object sender, RoutedEventArgs e)
        {
            currentLocation = new LocationData();
            currentLocation.Code = App.Settings.LocationCode;

            currentWeather = (WeatherData)XmlSerializable.Load(typeof(WeatherData), E.Root + "\\Weather.data") ?? new WeatherData();
            lastWeatherState = WeatherConverter.ConvertSkyCodeToWeatherState(currentWeather.Curent.SkyCode);

            if (string.IsNullOrEmpty(currentLocation.Code))
            {
                WeatherGrid.Visibility = System.Windows.Visibility.Collapsed;
                HLTempGrid.Visibility = System.Windows.Visibility.Collapsed;
                ForecastPanel.Visibility = System.Windows.Visibility.Collapsed;
                WeatherIcon.Visibility = System.Windows.Visibility.Collapsed;
                TemperatureTextBlock.Visibility = System.Windows.Visibility.Collapsed;
                SetupLocationTextBlock.Visibility = System.Windows.Visibility.Visible;
            }
            else
            {
                WeatherGrid.Visibility = System.Windows.Visibility.Visible;
                HLTempGrid.Visibility = System.Windows.Visibility.Visible;
                ForecastPanel.Visibility = System.Windows.Visibility.Visible;
                WeatherIcon.Visibility = System.Windows.Visibility.Visible;
                TemperatureTextBlock.Visibility = System.Windows.Visibility.Visible;
                SetupLocationTextBlock.Visibility = System.Windows.Visibility.Collapsed;
            }

            UpdateWeatherUI();
            lastWeatherState = WeatherState.None;

            weatherTimer = new DispatcherTimer();
            weatherTimer.Interval = TimeSpan.FromMinutes(App.Settings.RefreshInterval);
            weatherTimer.Tick += WeatherTimerTick;
            weatherTimer.Start();

            this.ShowInTaskbar = !App.Settings.UseTrayIcon;

            if (App.WpManager.CurrentProvider == null)
            {
                App.Settings.Provider = "MSN";
                App.WpManager.CurrentProvider = App.WpManager.Providers.Find(p => p.Name == "MSN");
                App.WpManager.CurrentProvider.Load();
            }

            if (currentLocation.Code != null)
                RefreshWeather();
        }

        private void WeatherTimerTick(object sender, EventArgs e)
        {
            RefreshWeather();
        }

        private void RefreshWeather()
        {
            WeatherRefreshProgressBar.Visibility = System.Windows.Visibility.Visible;
            Taskbar.ProgressState = TaskbarItemProgressState.Indeterminate;
            ThreadStart threadStarter = () =>
            {
                logger.Info("Getting weather report");
                var w = App.WpManager.CurrentProvider.GetWeatherReport(CultureInfo.GetCultureInfo(App.Settings.Language), currentLocation,
                        App.Settings.TempScale, App.Settings.WindSpeedScale, TimeZoneInfo.Local.BaseUtcOffset);
                if (w != null)
                {
                    logger.Info("Got weather report:");
                    logger.Info("Location: {0}", w.Location.Code);
                    logger.Info("Temperature: {0}", w.Temperature);
                    logger.Info("Feels like: {0}", w.FeelsLike);
                    logger.Info("Humidity: {0}", w.Humidity);
                    logger.Info("Wind speed: {0}", w.WindSpeed);
                    logger.Info("Skycode: {0}", w.Curent.SkyCode);
                    logger.Info("Text: {0}", w.Curent.Text);

                    currentWeather = w;

                    logger.Info("Updating weather UI");
                    UpdateWeatherUI();
                    logger.Info("Weather UI updated");
                }
                else
                    logger.Info("Weather report is null");

                WeatherRefreshProgressBar.Dispatcher.Invoke((Action)delegate
                {
                    WeatherRefreshProgressBar.Visibility = System.Windows.Visibility.Collapsed;
                });

                this.Dispatcher.Invoke((Action)delegate
                {
                    Taskbar.ProgressState = TaskbarItemProgressState.None;
                });

                currentWeather.Save(E.Root + "\\Weather.data");
            };
            var thread = new Thread(threadStarter);
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
        }

        private void UpdateWeatherUI()
        {
            WeatherGrid.Dispatcher.Invoke((Action)delegate
                                                       {
                                                           LocationTextBlock.Text = currentWeather.Location.City;
                                                           WeatherTextBlock.Text = currentWeather.Curent.Text;

                                                           var state = WeatherConverter.ConvertSkyCodeToWeatherState(currentWeather.Curent.SkyCode);
                                                           if (state != lastWeatherState && !string.IsNullOrEmpty(App.Settings.LocationCode))
                                                           {
                                                               SetWeatherState(state);
                                                           }


                                                           this.Icon = WeatherIcon.Source;
                                                           if (!string.IsNullOrEmpty(currentWeather.Curent.Text))
                                                               this.Title = currentWeather.Curent.Text;
                                                       });
            HLTempGrid.Dispatcher.Invoke((Action)delegate
                                           {
                                               if (App.Settings.ShowFeelsLike)
                                                   TemperatureTextBlock.Text = currentWeather.FeelsLike + "°";
                                               else
                                                   TemperatureTextBlock.Text = currentWeather.Temperature + "°";

                                               if (currentWeather.ForecastList.Count > 0)
                                               {
                                                   TemperatureHTextBlock.Text = currentWeather.ForecastList[0].HighTemperature + "°";
                                                   TemperatureLTextBlock.Text = currentWeather.ForecastList[0].LowTemperature + "°";
                                               }
                                           });

            HWGrid.Dispatcher.Invoke((Action)delegate
                                           {
                                               if (!App.Settings.ShowHW || string.IsNullOrEmpty(App.Settings.LocationCode))
                                                   HWGrid.Visibility = System.Windows.Visibility.Collapsed;
                                               else
                                               {
                                                   HWGrid.Visibility = System.Windows.Visibility.Visible;

                                                   switch (App.Settings.WindSpeedScale)
                                                   {
                                                       case WindSpeedScale.Mph:
                                                           WindSpeedValueTextBlock.Text = currentWeather.WindSpeed + " " + Properties.Resources.Mph;
                                                           break;
                                                       case WindSpeedScale.Kmh:
                                                           WindSpeedValueTextBlock.Text = currentWeather.WindSpeed + " " + Properties.Resources.Kmh;
                                                           break;
                                                       case WindSpeedScale.Ms:
                                                           WindSpeedValueTextBlock.Text = currentWeather.WindSpeed + " " + Properties.Resources.Ms;
                                                           break;
                                                   }

                                                   var windSpeedKmh = (int)WeatherConverter.WindSpeedConvertToKmh(currentWeather.WindSpeed, App.Settings.WindSpeedScale);

                                                   if (windSpeedKmh < 20)
                                                   {
                                                       WindSpeedIcon.Source = new BitmapImage(new Uri("/UIFramework.Weather;Component/Images/wind_lvl1.png", UriKind.Relative));
                                                   }

                                                   if (windSpeedKmh >= 20 && windSpeedKmh < 50)
                                                   {
                                                       WindSpeedIcon.Source = new BitmapImage(new Uri("/UIFramework.Weather;Component/Images/wind_lvl2.png", UriKind.Relative));
                                                   }

                                                   if (windSpeedKmh >= 50 && windSpeedKmh < 88)
                                                   {
                                                       WindSpeedIcon.Source = new BitmapImage(new Uri("/UIFramework.Weather;Component/Images/wind_lvl3.png", UriKind.Relative));
                                                   }
                                                   if (windSpeedKmh >= 88)
                                                   {
                                                       WindSpeedIcon.Source = new BitmapImage(new Uri("/UIFramework.Weather;Component/Images/wind_lvl4.png", UriKind.Relative));
                                                   }

                                                   HumidityValueTextBlock.Text = currentWeather.Humidity + "%";

                                                   if (currentWeather.Humidity < 25)
                                                       HumidityIcon.Source = new BitmapImage(new Uri("/UIFramework.Weather;Component/Images/humidity_lvl1.png", UriKind.Relative));
                                                   if (currentWeather.Humidity >= 25 && currentWeather.Humidity < 50)
                                                       HumidityIcon.Source = new BitmapImage(new Uri("/UIFramework.Weather;Component/Images/humidity_lvl2.png", UriKind.Relative));
                                                   if (currentWeather.Humidity >= 50 && currentWeather.Humidity < 75)
                                                       HumidityIcon.Source = new BitmapImage(new Uri("/UIFramework.Weather;Component/Images/humidity_lvl3.png", UriKind.Relative));
                                                   if (currentWeather.Humidity >= 75)
                                                       HumidityIcon.Source = new BitmapImage(new Uri("/UIFramework.Weather;Component/Images/humidity_lvl4.png", UriKind.Relative));
                                               }
                                           });

            WeatherIcon.Dispatcher.Invoke((Action)delegate
                                                       {
                                                           WeatherIcon.Source = new BitmapImage(new Uri(string.Format("/UIFramework.Weather;Component/Images/weather_{0}.png",
                                                              currentWeather.Curent.SkyCode), UriKind.Relative));
                                                       });


            ForecastPanel.Dispatcher.Invoke((Action)delegate
            {
                if (currentWeather.ForecastList.Count >= 5)
                {
                    var i = 1;
                    foreach (var item in ForecastPanel.Children)
                    {
                        if (item.GetType() == typeof(ForecastItemMetro))
                        {
                            var forecastItem = (ForecastItemMetro)item;
                            forecastItem.Temperature.Text = currentWeather.ForecastList[i].HighTemperature + "°/" +
                                currentWeather.ForecastList[i].LowTemperature + "°";
                            forecastItem.DayName.Text = DateTime.Now.AddDays(i).ToString("ddd").ToLower();
                            forecastItem.Icon.Source = new BitmapImage(new Uri(string.Format("/UIFramework.Weather;Component/Images/weather_{0}.png",
                                            currentWeather.ForecastList[i].SkyCode), UriKind.Relative));
                            forecastItem.ToolTip = currentWeather.ForecastList[i].Text + "\n" + Properties.Resources.ForecastTooltip;
                            forecastItem.Url = currentWeather.ForecastList[i].Url;
                            i++;
                        }
                    }
                }

            });
        }


        private void WindowMouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed && !App.Settings.Pin)
                DragMove();
        }

        private void WindowMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            App.Settings.Left = this.Left;
            App.Settings.Top = this.Top;
            App.Settings.Save(App.ConfigFile);
        }

        private void RefreshItemClick(object sender, RoutedEventArgs e)
        {
            RefreshWeather();
        }

        private void OptionsItemClick(object sender, RoutedEventArgs e)
        {
            if (optionsWindow != null && optionsWindow.IsVisible)
            {
                optionsWindow.Activate();
                return;
            }

            optionsWindow = new Options();
            optionsWindow.UpdateSettings += OptionsWindowUpdateSettings;

            optionsWindow.Width = App.Settings.OptionsWidth;
            optionsWindow.Height = App.Settings.OptionsHeight;

            if (App.Settings.Language == "he-IL" || App.Settings.Language == "ar-SA")
            {
                optionsWindow.FlowDirection = System.Windows.FlowDirection.RightToLeft;
            }
            else
            {
                optionsWindow.FlowDirection = System.Windows.FlowDirection.LeftToRight;
            }

            optionsWindow.ShowDialog();
        }

        private void OptionsWindowUpdateSettings(object sender, EventArgs e)
        {
            if (sender != null)
                currentLocation = (LocationData)sender;
            if (currentLocation.Code != null)
            {
                RefreshWeather();
            }

            if (weatherTimer.Interval.Minutes != App.Settings.RefreshInterval)
            {
                weatherTimer.Interval = TimeSpan.FromMinutes(App.Settings.RefreshInterval);
                weatherTimer.Stop();
                weatherTimer.Start();
            }

            if (string.IsNullOrEmpty(currentLocation.City) || string.IsNullOrEmpty(currentLocation.Code))
            {
                WeatherGrid.Visibility = System.Windows.Visibility.Collapsed;
                HLTempGrid.Visibility = System.Windows.Visibility.Collapsed;
                ForecastPanel.Visibility = System.Windows.Visibility.Collapsed;
                WeatherIcon.Visibility = System.Windows.Visibility.Collapsed;
                TemperatureTextBlock.Visibility = System.Windows.Visibility.Collapsed;
                SetupLocationTextBlock.Visibility = System.Windows.Visibility.Visible;
            }
            else
            {
                WeatherGrid.Visibility = System.Windows.Visibility.Visible;
                HLTempGrid.Visibility = System.Windows.Visibility.Visible;
                ForecastPanel.Visibility = System.Windows.Visibility.Visible;
                WeatherIcon.Visibility = System.Windows.Visibility.Visible;
                TemperatureTextBlock.Visibility = System.Windows.Visibility.Visible;
                SetupLocationTextBlock.Visibility = System.Windows.Visibility.Collapsed;
            }

            Scale.ScaleX = App.Settings.Scale;
            if (App.Settings.UseAero)
                UpdateAero();
            else
            {
                Dwm.RemoveGlassRegion(ref handle);
            }

            this.ShowInTaskbar = !App.Settings.UseTrayIcon;
            this.Opacity = App.Settings.Opacity;
        }

        private void CloseItemClick(object sender, RoutedEventArgs e)
        {
            currentWeather.Save(E.Root + "\\Weather.data");
            this.Close();
        }

        private void SunMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            SomeClouds.FadeOut();
            Sun.FadeIn();
        }

        private void SunMouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            SomeClouds.FadeIn();
            Sun.FadeOut();
        }

        private void UpdateAero()
        {
            double dpiX = 0.0f;
            double dpiY = 0.0f;
            var source = PresentationSource.FromVisual(this);
            if (source != null)
            {
                dpiX = source.CompositionTarget.TransformToDevice.M11;
                dpiY = source.CompositionTarget.TransformToDevice.M22;
            }

            var rgn = WinAPI.CreateRoundRectRgn(10, (int)(46 * App.Settings.Scale * dpiY), (int)((this.Width-10) * App.Settings.Scale * dpiX),
                (int)((this.Height-10) * App.Settings.Scale * dpiY), (int)(12 * App.Settings.Scale * dpiX), (int)(dpiY * App.Settings.Scale * 12));
            Dwm.MakeGlassRegion(ref handle, rgn);
        }

        private void TopMostItemClick(object sender, RoutedEventArgs e)
        {
            if (App.Settings.TopMost)
            {
                App.Settings.TopMost = false;
                this.Topmost = false;
            }
            else
            {
                App.Settings.TopMost = true;
                this.Topmost = true;
            }
        }

        private void SetWeatherState(WeatherState state)
        {
            //switch (state)
            //{
            //    case WeatherState.Clouds:
            //        StartCloudAnimation();
            //        break;
            //    case WeatherState.PartlyCloud:
            //        StartPartlyCloudAnim();
            //        break;
            //    case WeatherState.PartlySunny:
            //        StartPartlySunnyAnim();
            //        break;
            //    case WeatherState.HeavyRain:
            //        StartRainAnim();
            //        break;
            //    case WeatherState.SmallRain:
            //        StartRainAnim();
            //        break;
            //    case WeatherState.Storm:
            //        StartLightningAnim();
            //        break;
            //    case WeatherState.Clear:
            //        StartClearAnim();
            //        break;
            //    case WeatherState.Fog:
            //        StartFogAnim();
            //        break;
            //    case WeatherState.Wind:
            //        StartWindAnim();
            //        break;
            //}
        }

        private void StartClearAnim()
        {
            if (!File.Exists(E.Root + "\\Extras\\WeatherAnimation\\weather_sunny.mp4") || !File.Exists(E.Root + "\\Extras\\WeatherAnimation\\weather_clear.mp4"))
                return;
            var calc = new SunCalculator(DateTime.Now, currentWeather.Location.Lat, currentWeather.Location.Lon);
            var isDay = DateTime.Now > calc.DSunRise && DateTime.Now < calc.DSunSet;
            if (isDay)
                MediaElement.Source = new Uri(E.Root + "\\Extras\\WeatherAnimation\\weather_sunny.mp4");
            else
                MediaElement.Source = new Uri(E.Root + "\\Extras\\WeatherAnimation\\weather_clear.mp4");
            var s = (Storyboard)Resources["ShowVideoAnim"];
            s.Begin();
            MediaElement.Play();
        }

        private void MediaElementMediaEnded(object sender, RoutedEventArgs e)
        {
            MediaElement.Position = new TimeSpan();
            var s = (Storyboard)Resources["HideVideoAnim"];
            s.Begin();
        }

        private void ClearItem_Click(object sender, RoutedEventArgs e)
        {
            StartClearAnim();
        }

        private void PinItemClick(object sender, RoutedEventArgs e)
        {
            App.Settings.Pin = PinItem.IsChecked;
            App.Settings.Save(App.ConfigFile);
        }

        private void MouseEnterCompleted(object sender, EventArgs e)
        {
            this.Opacity = 1;
        }

        private void MouseLeaveCompleted(object sender, EventArgs e)
        {
            this.Opacity = App.Settings.Opacity;
        }

        private void ThisMouseEnter(object sender, MouseEventArgs e)
        {
            var mouseEnterAnim = (Storyboard)Resources["MouseEnter"];
            mouseEnterAnim.Begin(this);
        }

        private void ThisMouseLeave(object sender, MouseEventArgs e)
        {
            var mouseLeaveAnim = (Storyboard)Resources["MouseLeave"];
            ((DoubleAnimation)mouseLeaveAnim.Children[0]).To = App.Settings.Opacity;
            mouseLeaveAnim.Begin(this);
        }
    }
}
